#include <itkSeededRegionGrowingImageFilter.h>
#include <itkOrientImageFilter.h>
#include "tclap/CmdLine.h"
#include "ioutils.h"

typedef class CmdLineType
{
public:
  std::string InputIm, OutputIm, MarkerIm;
};

void ParseCmdLine(int argc, char* argv[],
                  CmdLineType &CmdLineObj
                  )
{
  using namespace TCLAP;
  try
    {
    // Define the command line object.
    CmdLine cmd("scaleWS ", ' ', "0.9");

    ValueArg<std::string> inArg("i","input","input image",true,"result","string");
    cmd.add( inArg );

    ValueArg<std::string> markArg("m","marker","marker image",true,"result","string");
    cmd.add( markArg );

    ValueArg<std::string> outArg("o","output","output image", true,"","string");
    cmd.add( outArg );

    // Parse the args.
    cmd.parse( argc, argv );

    CmdLineObj.InputIm = inArg.getValue();
    CmdLineObj.OutputIm = outArg.getValue();
    CmdLineObj.MarkerIm = markArg.getValue();

    }
  catch (ArgException &e)  // catch any exceptions
    {
    std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
    }
}
////////////////////////////////////////////////////////
template <class PixType, class LabPixType, int dim>
void doWatershed(const CmdLineType &CmdLineObj)
{
  typedef typename itk::Image<PixType, dim> RawImType;
  typedef typename itk::Image<LabPixType, dim> LabImType;

  // gradients computed using the raw pixel type
  typedef typename itk::SeededRegionGrowingImageFilter<RawImType, LabImType> SRGFiltType;

  typename RawImType::Pointer input = readIm<RawImType>(CmdLineObj.InputIm);

  // orientation related parts break the 2D case
  typedef typename itk::OrientImageFilter<LabImType, LabImType> OrientType;
  typename OrientType::Pointer orienter = OrientType::New();
  itk::SpatialOrientationAdapter orientAd;

  orienter->SetInput(readIm<LabImType>(CmdLineObj.MarkerIm));
  orienter->UseImageDirectionOn();
  orienter->SetDesiredCoordinateOrientation(orientAd.FromDirectionCosines(input->GetDirection()));
  typename SRGFiltType::Pointer srgfilt = SRGFiltType::New();
  srgfilt->SetInput(input);
  srgfilt->SetMarkBoundaryLine(false);
  srgfilt->SetFullyConnected(true);
  srgfilt->SetMarkerImage(orienter->GetOutput());
  std::cout << "started srg" << std::endl;
//	typename LabImType::Pointer markers = orienter->GetOutput();
//	markers->Update();
//	std::cout << input;
//	std::cout << markers;
  typename LabImType::Pointer res = srgfilt->GetOutput();
  res->Update();
  res->DisconnectPipeline();
  res->CopyInformation(input);
  writeIm<LabImType>(res, CmdLineObj.OutputIm);

}
////////////////////////////////////////////////////////
int main(int argc, char * argv[])
{

  int dim1, dim2 = 0;
  CmdLineType CmdLineObj;
  ParseCmdLine(argc, argv, CmdLineObj);
//  itk::MultiThreader::SetGlobalMaximumNumberOfThreads(1);
  itk::ImageIOBase::IOComponentType ComponentType, MarkerComponentType;

  if (!readImageInfo(CmdLineObj.InputIm, &ComponentType, &dim1))
    {
    std::cerr << "Failed to open " << CmdLineObj.InputIm << std::endl;
    return(EXIT_FAILURE);
    }
  if (!readImageInfo(CmdLineObj.MarkerIm, &MarkerComponentType, &dim2))
    {
    std::cerr << "Failed to open " << CmdLineObj.MarkerIm << std::endl;
    return(EXIT_FAILURE);
    }

  if (dim1 != dim2)
    {
    std::cerr << "Image dimensions must match " << dim1 << " " << dim2 << std::endl;
    return(EXIT_FAILURE);

    }
  
// this will be a big, ugly switch statement to handle all the cases
// we want char, short and int markers, char, short, unsigned short,
// and float raw images
  switch (dim1)
    {
    case 2:
    {
//#define WSDIM 2
//#include "nasty_switch.h"
//#undef WSDIM
    }
    break;
    case 3:
    {
#define WSDIM 3
#include "nasty_switch.h"
#undef WSDIM
    }
    break;
    default:
      std::cerr << "Unsupported dimension" << std::endl;
      break;
    }

  return EXIT_SUCCESS;
}
